
#include "sqldata.h"
#include <Windows.h>
#define LOG  printf
CSqlData::CSqlData()
{
	::GetModuleFileNameA(NULL, m_strDBPath, MAX_PATH);
	char* strPos = strrchr(m_strDBPath, '\\');
	strPos[1] = '\0';
	strcat_s(m_strDBPath, "safewall.db");
	m_db = NULL;
	sqlite3_open(m_strDBPath, &m_db);
}

CSqlData::~CSqlData()
{
	if (m_db)
	{
		sqlite3_close(m_db);
		m_db = NULL;
	}
}

bool CSqlData::TakeUserInfo(const std::string& access, const std::string& password, Json::Value& root)
{
	bool ret = false;
	sqlite3_stmt* stmt;
	std::string sql = "select id, access, password, username, email from users where access='" + access + "';";
	int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
	if (rc != SQLITE_OK) {
		LOG("TakeUserInfo->SQL error: %s\n", sqlite3_errmsg(m_db));
		return ret;
	}

	do {
		if ((rc = sqlite3_step(stmt)) != SQLITE_ROW) {
			LOG("TakeUserInfo->SQL error: %s\n", sqlite3_errmsg(m_db));
			break;
		}
		int id = sqlite3_column_int(stmt, 0);
		const unsigned char* user = sqlite3_column_text(stmt, 1);
		if (0 != _strcmpi(access.c_str(), (char*)user))
		{
			break;
		}
		const unsigned char* pwd = sqlite3_column_text(stmt, 2);
		if (0 != _strcmpi(password.c_str(), (char*)pwd))
		{
			break;
		}
		const unsigned char* username = sqlite3_column_text(stmt, 3);
		const unsigned char* email = sqlite3_column_text(stmt, 4);
		
		email = email ? email : (const unsigned char*)"";

		root["username"] = (char*)username;
		root["email"] = (char*)email;

		GUID guid;
		char token[39];
		CoCreateGuid(&guid);
		snprintf(token, sizeof(token), "{%08x-%04x-%04x-%04x-%012llx}",
			guid.Data1, guid.Data2, guid.Data3, (guid.Data4[0] << 8) | guid.Data4[1],
			*((unsigned long long*) & guid.Data4[2]));
		root["token"] = token;
		ret = true;
	} while (0);

	sqlite3_finalize(stmt);
	return ret;
}

bool CSqlData::TakePermissions(const std::string& access, Json::Value& root)
{
	bool ret = false;
	sqlite3_stmt* stmt;
	std::string sql = "SELECT menu,suffix,skip_suffix,process,skip_process,"
		"network,skip_network FROM permissions WHERE access='" + access + "';";
	int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
	if (rc != SQLITE_OK) {
		LOG("TakePermissions->SQL error: %s\n", sqlite3_errmsg(m_db));
		return false;
	}

	if ((rc = sqlite3_step(stmt)) != SQLITE_ROW) {
		LOG("TakePermissions->SQL error: %s\n", sqlite3_errmsg(m_db));
		sqlite3_finalize(stmt);
		return false;
	}

	int menu = sqlite3_column_int(stmt, 0);
	const unsigned char* suffix = sqlite3_column_text(stmt, 1);
	const unsigned char* skip_suffix = sqlite3_column_text(stmt, 2);
	const unsigned char* process = sqlite3_column_text(stmt, 3);
	const unsigned char* skip_process = sqlite3_column_text(stmt, 4);
	const unsigned char* network = sqlite3_column_text(stmt, 5);
	const unsigned char* skip_network = sqlite3_column_text(stmt, 6);

	suffix = suffix ? suffix : (const unsigned char*)"";
	skip_suffix = skip_suffix ? skip_suffix : (const unsigned char*)"";
	process = process ? process : (const unsigned char*)"";
	skip_process = skip_process ? skip_process : (const unsigned char*)"";
	network = network ? network : (const unsigned char*)"";
	skip_network = skip_network ? skip_network : (const unsigned char*)"";

	do {
		if (false == TakeSuffix((char*)suffix , "suffix", root)) {
			break;
		}
		if (false == TakeSuffix((char*)skip_suffix, "skip_suffix", root)) {
			break;
		}
		if (false == TakeNetwork((char*)network, "network", root)) {
			break;
		}
		if (false == TakeNetwork((char*)skip_network, "skip_network", root)) {
			break;
		}
		if (false == TakePorcess((char*)process, "process", root)) {
			break;
		}
		if (false == TakePorcess((char*)skip_process, "skip_process", root)) {
			break;
		}
		if (false == TakeConf((char*)access.c_str(), "user_conf", root)) {
			//break;
		}
		ret = true;
	} while (0);

	sqlite3_finalize(stmt);
	if (false == ret) {
		root.clear();
	}
	
	return true;
}

bool CSqlData::TakeConf(const char* access, const char* key, Json::Value& root)
{
	Json::Value value;
	sqlite3_stmt* stmt;
	bool ret = false;
	std::string sql = "SELECT showicon,showfile FROM user_conf WHERE access='";
	sql.append(access);
	sql.append("';");
	int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL);
	if (rc != SQLITE_OK) {
		LOG("TakeConf->SQL error: %s\n", sqlite3_errmsg(m_db));
		return false;
	}

	do {
		if ((rc = sqlite3_step(stmt)) != SQLITE_ROW) {
			LOG("TakeConf->SQL error: %s\n", sqlite3_errmsg(m_db));
			break;
		}
		int showicon = sqlite3_column_int(stmt, 0);
		int showfile = sqlite3_column_int(stmt, 0);

		value["showicon"] = showicon;
		value["showfile"] = showfile;
		root[key] = value;
		ret = true;
	} while (0);
	sqlite3_finalize(stmt);
	return ret;
}

bool CSqlData::TakePorcess(const char* condition, const char* key, Json::Value& root)
{
	Json::Value value;
	sqlite3_stmt* stmt;
	char* context = NULL;
	condition = strtok_s((char*)condition, ";", &context);
	if (NULL == condition) {
		return true;
	}
	std::string sql = "SELECT pename, sha256, sign  FROM process WHERE id IN(";

	while (condition != NULL) {
		sql.append(condition);
		sql.push_back(',');
		condition = strtok_s(NULL, ";", &context);
	}
	sql[sql.size() - 1] = ')';
	sql.push_back(';');

	if (SQLITE_OK != sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL)) {
		LOG("TakePorcess->SQL error: %s\n", sqlite3_errmsg(m_db));
		return false;
	}

	while (SQLITE_ROW == sqlite3_step(stmt))
	{
		const char* pename = (const char*)sqlite3_column_text(stmt, 0);
		const char* sha256 = (const char*)sqlite3_column_text(stmt, 0);
		const char* sign = (const char*)sqlite3_column_text(stmt, 0);
		pename = pename ? pename : (const char*)"";
		sha256 = sha256 ? sha256 : (const char*)"";
		sign = sign ? sign : (const char*)"";

		Json::Value data;
		data["pename"] = pename;
		data["sha256"] = sha256;
		data["sign"] = sign;
		value.append(data);
	}
	LOG("TakePorcess->SQL error: %s\n", sqlite3_errmsg(m_db));
	root[key] = value;
	sqlite3_finalize(stmt);
	return true;
}

bool CSqlData::TakeNetwork(const char* condition, const char* key, Json::Value& root)
{
	Json::Value value;
	sqlite3_stmt* stmt;
	char* context = NULL;
	condition = strtok_s((char*)condition, ";", &context);
	if (NULL == condition) {
		return true;
	}
	std::string sql = "SELECT host, protocol FROM network WHERE id IN(";

	while (condition != NULL) {
		sql.append(condition);
		sql.push_back(',');
		condition = strtok_s(NULL, ";", &context);
	}
	sql[sql.size() - 1] = ')';
	sql.push_back(';');

	if (SQLITE_OK != sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL)) {
		LOG("TakeNetwork->SQL error: %s\n", sqlite3_errmsg(m_db));
		return false;
	}

	while (SQLITE_ROW == sqlite3_step(stmt))
	{
		const char* host = (const char*)sqlite3_column_text(stmt, 0);
		const char* protocol = (const char*)sqlite3_column_text(stmt, 0);
		host = host ? host : (const char*)"";
		protocol = protocol ? protocol : (const char*)"";

		Json::Value data;
		data["host"] = host;
		data["protocol"] = protocol;
		value.append(data);
	}
	LOG("TakeNetwork->SQL error: %s\n", sqlite3_errmsg(m_db));
	root[key] = value;
	sqlite3_finalize(stmt);
	return true;
}

bool CSqlData::TakeSuffix(const char* condition, const char* key, Json::Value& root)
{
	Json::Value value;
	sqlite3_stmt* stmt;
	char* context = NULL;  

	condition = strtok_s((char*)condition, ";", &context);
	if (NULL == condition) {
		return true;
	}
	std::string sql = "SELECT sname FROM suffix WHERE id IN(";

	while (condition != NULL) {
		sql.append(condition);
		sql.push_back(',');
		condition = strtok_s(NULL, ";", &context);
	}
	sql[sql.size() - 1] = ')';
	sql.push_back(';');

	if (SQLITE_OK != sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, NULL)) {
		LOG("TakeSuffix->SQL error: %s\n", sqlite3_errmsg(m_db));
		return false;
	}

	while (SQLITE_ROW == sqlite3_step(stmt)) 
	{
		const char* suffix = (const char*)sqlite3_column_text(stmt, 0);
		suffix = suffix ? suffix : (const char*)"";
		suffix = strtok_s((char*)suffix, ";", &context);
		while (suffix != NULL) {
			value.append(suffix);
			suffix = strtok_s(NULL, ";", &context);
		}
	} 
	LOG("TakeSuffix->SQL error: %s\n", sqlite3_errmsg(m_db));
	root[key] = value;
	sqlite3_finalize(stmt);
	return true;
}